package cn.kkcxy.blog.server.controller;

import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.stp.StpUtil;
import cn.kkcxy.blog.common.constant.ExceptionMessageConstant;
import cn.kkcxy.blog.common.utils.IpUtil;
import cn.kkcxy.blog.core.dto.client.LoginParamsDTO;
import cn.kkcxy.blog.core.exception.auth.ValidCodeException;
import cn.kkcxy.blog.core.result.ResponseEntity;
import cn.kkcxy.blog.core.vo.LoginVO;
import cn.kkcxy.blog.core.vo.admin.AdministratorInfoVO;
import cn.kkcxy.blog.core.vo.admin.RouterVO;
import cn.kkcxy.blog.system.factory.login.LoginTypeHandler;
import cn.kkcxy.blog.system.factory.login.LoginTypeHandlerFactory;
import cn.kkcxy.blog.system.service.AuthService;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * @BelongsProject: kkcxy-blog
 * @BelongsPackage: cn.kkcxy.blog.server.controller
 * @Author: kkcxy
 * @CreateTime: 2024-09-12 02:15
 * @Description: 认证服务 - controller
 * @Version: 1.0
 */
@Tag(name = "认证服务")
@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController {

    /**
     * auth service impl
     */
    @Resource
    private AuthService authService;

    /**
     * 获得类型处理器工厂
     */
    @Resource
    private LoginTypeHandlerFactory loginTypeHandlerFactory;

    /**
     * @description: 登录接口
     * @author: kkcxy
     * @date: 2024/9/12 2:12
     * @param: [code, loginType, loginParamsDTO]
     * @return: cn.kkcxy.weblog.common.base.result.ResponseEntity
     **/
    @SaIgnore
    @PostMapping("/login")
    @Operation(summary = "登录接口")
    public ResponseEntity<LoginVO> login(
            @Parameter(hidden = true) HttpServletRequest request,
            @RequestParam(value = "validCode", required = false) String code,
            @RequestParam(value = "loginType", required = false) Integer loginType,
            @RequestBody(required = false) LoginParamsDTO loginParamsDTO) {
        String ip = IpUtil.getIpAddr(request);
        // 打印日志
        if (log.isInfoEnabled())
            log.info("ip: {}, path: /auth/login, requestParams: code = {}, loginType = {}, dto:  {}", ip, code, loginType, JSON.toJSONString(loginParamsDTO));
        // 执行业务
        return authService.login(code, loginType, loginParamsDTO, ip);
    }

    /**
     * @description: 获取验证码
     * @author: kkcxy
     * @date: 2024/9/12 2:15
     * @param: [response, type]
     * @return: cn.kkcxy.weblog.common.base.result.ResponseEntity
     **/
    @SaIgnore
    @GetMapping("/code/{type}")
    @Operation(summary = "获取验证码")
    public ResponseEntity<Object> getCode(
            @Parameter(hidden = true) HttpServletResponse response,
            @RequestParam("account") String account,
            @PathVariable Integer type) throws IOException {
        // 打印日志
        if (log.isInfoEnabled()) {
            log.info("path: /auth/code/{}, account = {}", type, account);
        }
        if (type == null) throw new ValidCodeException(ExceptionMessageConstant.GET_VALID_CODE_ERROR);
        // 获取对应类型处理器
        LoginTypeHandler handler = loginTypeHandlerFactory.getHandlerByLoginType(type);
        // 判断处理器是否存在
        if (Objects.isNull(handler)) {
            throw new ValidCodeException(ExceptionMessageConstant.GET_VALID_CODE_ERROR);
        }
        // 执行业务
        return handler.getCode(response, account);
    }

    /**
     * @description: 判断管理员Token是否过期
     * @author: kkcxy
     * @date: 2024/10/21 1:05
     * @param: []
     * @return: cn.kkcxy.blog.core.result.ResponseEntity<java.lang.Object>
     **/
    @SaCheckOr(login = @SaCheckLogin, role = @SaCheckRole("*_admin"))
    @Operation(summary = "判断管理员登录状态是否过期")
    @GetMapping("/administrator/logged/in")
    public ResponseEntity<Object> administratorAlreadyLoggedIn() {
        Long adminId = Long.parseLong(String.valueOf(StpUtil.getLoginId()));
        log.info("管理员Token是否过期 id: {}", adminId);
        return ResponseEntity.success();
    }

    /**
     * @description: 获取管理员路由信息
     * @author: kkcxy
     * @date: 2024/10/24 1:52
     * @param: []
     * @return: cn.kkcxy.blog.core.result.ResponseEntity<java.util.List<cn.kkcxy.blog.core.vo.admin.RouterVO>>
     **/
    @SaCheckLogin
    @Operation(summary = "获取管理员路由信息")
    @GetMapping("/administrator/get-routers")
    public ResponseEntity<List<RouterVO>> getAdministratorRouters() {
        Long adminId = Long.parseLong(String.valueOf(StpUtil.getLoginId()));
        return ResponseEntity.success(authService.getAdminRouters(adminId));
    }

    /**
     * @description: 获取管理员账号信息
     * @author: kkcxy
     * @date: 2024/10/29 0:51
     * @param: []
     * @return: cn.kkcxy.blog.core.result.ResponseEntity<java.util.List<cn.kkcxy.blog.core.vo.admin.RouterVO>>
     **/
    @SaCheckLogin
    @Operation(summary = "获取管理员账号信息")
    @GetMapping("/administrator/get-info")
    public ResponseEntity<AdministratorInfoVO> getAdministratorInfo() {
        Long adminId = Long.parseLong(String.valueOf(StpUtil.getLoginId()));
        return ResponseEntity.success(authService.getAdministratorInfo(adminId));
    }

    /**
     * @description: 退出登录
     * @author: kkcxy
     * @date: 2024/10/29 2:15
     * @param: []
     * @return: cn.kkcxy.blog.core.result.ResponseEntity<java.lang.Object>
     **/
    @SaIgnore
    @GetMapping("/logout")
    @Operation(summary = "退出登录")
    public ResponseEntity<Object> logout(String token) {
        log.info("logout token: {}", token);
        StpUtil.logoutByTokenValue(token);
        return ResponseEntity.success();
    }
}
